/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ExpandablePopupMenuPackage;

import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.util.Vector;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 *
 * @author Heather
 */
public class ExpandablePopupMenu extends JPopupMenu
{
  // this is the JTree representing the structure of the ascriptives

  private JTree ascriptives;
  // this is the JTree node representing what menu item is selected
  // NEED TO SET THIS TO NULL AGAIN WHEN EXITED
  private DefaultMutableTreeNode selectedItem = null;

  public ExpandablePopupMenu(JTree ascriptives)
  {
    super();
    setupMenu(ascriptives);
  }

  // basically BFS on the tree to construct the menus
  public void setupMenu(JTree ascriptives)
  {
    this.ascriptives = ascriptives;
    Vector<DefaultMutableTreeNode> queue = new Vector<DefaultMutableTreeNode>();
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) ascriptives.getModel().getRoot();

    // add root's children to the queue
    for (int i = 0; i < root.getChildCount(); i++)
    {
      queue.add((DefaultMutableTreeNode) root.getChildAt(i));
    }

    // this lets us keep track of what parent the popped nodes belong to
    DefaultMutableTreeNode parentNode = root;
    // this stores the parents, which is really just jmenus of the previous
    // layer in the tree
    Vector<JComponent> parentMenus = new Vector<JComponent>();
    JComponent parentMenu = this;

    while (queue.size() > 0)
    {
      // pop current
      DefaultMutableTreeNode currentNode = queue.get(0);
      queue.remove(currentNode);

      // check that the parent is OK
      if (!parentNode.equals(currentNode.getParent()))
      {
        parentNode = (DefaultMutableTreeNode) currentNode.getParent();
        // the parent menu is the first node in the previous layer
        parentMenu = parentMenus.get(0);
        parentMenus.remove(parentMenu);
      }

      // add current to the menu
      // whether this is a submenu or not depends on whether the current has children
      if (currentNode.getChildCount() > 0)
      {
        // add this node to the menu as a submenu
        String name = (String) currentNode.getUserObject();
        JMenu currentMenu = new JMenu(name);
        currentMenu.setName(name);
        parentMenu.add(currentMenu);

        // if the node has parents, add it to the parent vector
        parentMenus.add(currentMenu);

        // setup listeners for this currentMenu
        setupMenuListener(currentMenu);

        // queue children
        for (int i = 0; i < currentNode.getChildCount(); i++)
        {
          queue.add((DefaultMutableTreeNode) currentNode.getChildAt(i));
        }
      } else
      {
        // add this node to the menu as a menu item
        String name = (String) currentNode.getUserObject();
        JMenuItem nodeItem = new JMenuItem(name);
        nodeItem.setName(name);
        parentMenu.add(nodeItem);

        // setup listeners for this item
        setupMenuListener(nodeItem);
      }
    }
  }

  // disable the particular entry w/ this name
  public void disableEntry(String name)
  {
    Vector<JComponent> queue = new Vector<JComponent>();

    // add all the immediate submenus
    for (int i = 0; i < this.getComponentCount(); i++)
    {
      queue.add((JComponent) this.getComponent(i));
    }

    boolean done = false;
    while (!done)
    {
      // pop top
      JComponent c = queue.get(0);
      queue.remove(c);

      if (c.getName().equals(name))
      {
        c.setEnabled(false);
        done = true;
      }

      // queue children
      if (c.getClass() == JMenu.class)
      {
        for (int i = 0; i < ((JMenu) c).getMenuComponentCount(); i++)
        {
          queue.add((JComponent) ((JMenu) c).getMenuComponent(i));
        }
      }

      // stop if none found
      if (queue.size() == 0)
      {
        done = true;
      }
    }
  }

  // sets all menus to enabled true
  public void enableAll()
  {
    Vector<JComponent> queue = new Vector<JComponent>();

    // add all the immediate submenus
    for (int i = 0; i < this.getComponentCount(); i++)
    {
      queue.add((JComponent) this.getComponent(i));
    }

    while (queue.size() > 0)
    {
      // pop top
      JComponent c = queue.get(0);
      queue.remove(c);
      c.setEnabled(true);

      // queue children
      if (c.getClass() == JMenu.class)
      {
        for (int i = 0; i < ((JMenu) c).getMenuComponentCount(); i++)
        {
          queue.add((JComponent) ((JMenu) c).getMenuComponent(i));
        }
      }
    }
  }

  public void setupMenuListener(final JComponent c)
  {
    c.addMouseListener(new java.awt.event.MouseAdapter()
    {

      public void mouseEntered(java.awt.event.MouseEvent evt)
      {
        // do BFS to get DefaultMutableTreeNode we need
        Vector<DefaultMutableTreeNode> queue = new Vector<DefaultMutableTreeNode>();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) ascriptives.getModel().getRoot();

        // queue children
        for (int i = 0; i < root.getChildCount(); i++)
        {
          queue.add((DefaultMutableTreeNode) root.getChildAt(i));
        }

        boolean found = false;
        while (!found)
        {
          // pop first
          DefaultMutableTreeNode current = queue.get(0);
          queue.remove(current);

          if (current.getUserObject().equals(c.getName()))
          {
            found = true;
            selectedItem = current;
          } else
          {
            if (!current.isLeaf())
            {
              for (int j = 0; j < current.getChildCount(); j++)
              {
                queue.add((DefaultMutableTreeNode) current.getChildAt(j));
              }
            }
          }
        }
      }

      public void mouseExited(java.awt.event.MouseEvent evt)
      {
        selectedItem = null;
      }
    });
  }

  public DefaultMutableTreeNode getSelectedItem()
  {
    return selectedItem;
  }

  // adds the supplied listener to all menus
  public void addMouseListenerToAll(MouseAdapter inputListener)
  {
    Vector<JComponent> queue = new Vector<JComponent>();
    this.addMouseListener(inputListener);

    // add all the immediate submenus
    for (int i = 0; i < this.getComponentCount(); i++)
    {
      queue.add((JComponent) this.getComponent(i));
    }

    while (queue.size() > 0)
    {
      // pop top
      JComponent c = queue.get(0);
      queue.remove(c);
      c.addMouseListener(inputListener);

      // queue children
      if (c.getClass() == JMenu.class)
      {
        for (int i = 0; i < ((JMenu) c).getMenuComponentCount(); i++)
        {
          queue.add((JComponent) ((JMenu) c).getMenuComponent(i));
        }
      }
    }
  }

  public void addActionListenerToAll(ActionListener inputListener)
  {
    Vector<JMenuItem> queue = new Vector<JMenuItem>();

    // add all the immediate submenus
    for (int i = 0; i < this.getComponentCount(); i++)
    {
      queue.add((JMenuItem) this.getComponent(i));
    }

    while (queue.size() > 0)
    {
      // pop top
      JMenuItem c = queue.get(0);
      queue.remove(c);
      c.addActionListener(inputListener);

      // queue children
      if (c.getClass() == JMenu.class)
      {
        for (int i = 0; i < ((JMenu) c).getMenuComponentCount(); i++)
        {
          queue.add((JMenuItem) ((JMenu) c).getMenuComponent(i));
        }
      }
    }
  }

  // returns the siblings of this input node
  public Vector<DefaultMutableTreeNode> getSiblings(DefaultMutableTreeNode inputNode)
  {
    Vector<DefaultMutableTreeNode> ret = new Vector<DefaultMutableTreeNode>();
    DefaultMutableTreeNode parent = (DefaultMutableTreeNode) inputNode.getParent();

    if (parent != null)
    {
      for (int i = 0; i < parent.getChildCount(); i++)
      {
        ret.add((DefaultMutableTreeNode) parent.getChildAt(i));
      }
    }

    return ret;
  }

  // returns the leaves of given node
  public Vector<DefaultMutableTreeNode> getAllLeaves(DefaultMutableTreeNode inputNode)
  {
    Vector<DefaultMutableTreeNode> ret = new Vector<DefaultMutableTreeNode>();
    Vector<DefaultMutableTreeNode> queue = new Vector<DefaultMutableTreeNode>();
    queue.add(inputNode);

    while(queue.size() > 0)
    {
      // pop
      DefaultMutableTreeNode node = queue.get(0);
      queue.remove(node);

      if (node.isLeaf())
        ret.add(node);
      else
      {
        for (int i = 0; i < node.getChildCount(); i++)
        {
          queue.add((DefaultMutableTreeNode)node.getChildAt(i));
        }
      }
    }
    return ret;
  }

  // note: input node MUST BELONG TO THIS EXP MENU
  // returns -1 if not found
  public int getCategoryIndexOfNode(DefaultMutableTreeNode inputNode)
  {
    // search through the categories for the node
    DefaultMutableTreeNode root = (DefaultMutableTreeNode)ascriptives.getModel().getRoot();
    int ret = -1;
    for (int i = 0; i < root.getChildCount(); i++)
    {
      DefaultMutableTreeNode category = (DefaultMutableTreeNode)root.getChildAt(i);

      // use bfs to find inputnode
      Vector<DefaultMutableTreeNode> queue = new Vector<DefaultMutableTreeNode>();
      queue.add(category);
      boolean done = false;

      while(!done)
      {
        DefaultMutableTreeNode pop = queue.get(0);
        queue.remove(pop);

        if (pop.equals(inputNode))
        {
          done = true;
          ret = i;
        }
        else
        {
          for (int j = 0; j < pop.getChildCount(); j++)
          {
            queue.add((DefaultMutableTreeNode)pop.getChildAt(j));
          }
        }
        if (queue.size() == 0)
          done = true;
      }

      if (ret != -1)
        return ret;
    }

    return ret;
  }
}
